﻿using System.Collections.Generic;
using UnityEngine;

namespace UnityView
{
    // 列表视图（高度可变）适配器
    public interface IListAdapter
    {
        int GetCount();
        IViewLayout GetConvertView(int index, IViewLayout view);
        float GetItemSize(int index);
    }

    // 列表视图，每一行的高度可不相同
    public class ListView : AbsAdapterView<IListAdapter>
    {
        public ListView(string name = "List View") : this(UICanvas.GetInstance(), name)
        {
        }

        public ListView(IViewLayout parent, string name = "List View") : base(parent, name)
        {
        }

        public float AnchorFooter
        {
            get
            {
                if (ItemCount == 0 || SizeCache == null || AnchorCache == null) return HeaderViewSize;
                return AnchorCache[AnchorCache.Count - 1] + HeaderViewSize;
            }
        }

        public override void ScrollToTop(int index = 0)
        {
            if (index < 0 || index >= AnchorCache.Count)
            {
                ContentTransform.anchoredPosition = Vector2.zero;
                return;
            }

            ContentTransform.anchoredPosition = new Vector2(0, AnchorCache[index]);
            StartIndex = GetStartIndex();
            UpdateVisibleItemCount();
        }

        // 高度缓存数组
        protected List<float> SizeCache = new List<float>();

        // 起点缓存数组
        protected List<float> AnchorCache = new List<float>();

        public override void OnAdapterAttached(IListAdapter adapter)
        {
            ItemCount = adapter.GetCount();
            UpdateSizeCache();
            Reload();
            RepositionFooter();
        }

        // 更新高度缓存，返回更新元素的数目
        public int UpdateSizeCache()
        {
            int newCount = Adapter.GetCount();
            int diff = newCount - ItemCount;
            ItemCount = newCount;
            
            if (diff > 0)
            {
                float anchor = 0;
                if (SizeCache.Count > 0)
                {
                    anchor = AnchorCache[AnchorCache.Count - 1] + SizeCache[SizeCache.Count - 1];
                }

                for (int i = SizeCache.Count; i < ItemCount; i++)
                {
                    float height = Adapter.GetItemSize(i);
                    SizeCache.Add(height);
                    AnchorCache.Add(anchor);
                    anchor += height;
                }
            }
            else
            {
                SizeCache.RemoveRange(SizeCache.Count + diff, -diff);
                AnchorCache.RemoveRange(AnchorCache.Count + diff, -diff);
            }

            UpdateVisibleItemCount();

            return diff;
        }

        // 重载高度缓存
        public void ReloadSizeCache()
        {
            SizeCache.Clear();
            AnchorCache.Clear();
            ItemCount = 0;
            UpdateSizeCache();
        }

        // 当前可见的元素集合，这是一个双向链表
        public LinkedList<AdapterCellHolder> Items = new LinkedList<AdapterCellHolder>();

        // 缓存的元素集合
        public AdapterCellCache<AdapterCellHolder> Cache = new AdapterCellCache<AdapterCellHolder>();

        public override UILayout Header
        {
            get { return base.Header; }
            set
            {
                base.Header = value;
                value.RectTransform.SetParent(ContentTransform);
                value.RectTransform.anchoredPosition = Vector2.zero;
                UpdateContentSize();
            }
        }

        public override UILayout Footer
        {
            get { return base.Footer; }
            set
            {
                base.Footer = value;
                UpdateContentSize();
                RepositionFooter();
            }
        }

        // public void OnItemSizeChanged()
        // {
        //     float anchor = 0;
        //     for (int i = 0; i < ItemCount; i++)
        //     {
        //         float height = Adapter.GetItemSize(i);
        //         SizeCache[i] = height;
        //         AnchorCache[i] = anchor;
        //         anchor += height;
        //     }
        // }
        //
        // public void OnItemSizeChanged(int index)
        // {
        //     if (ItemCount <= index)
        //     {
        //         throw new IndexOutOfRangeException("改变的元素超过ListView的最大容量");
        //     }
        //
        //     SizeCache[index] = Adapter.GetItemSize(index);
        //     float anchor = index > 0 ? AnchorCache[index - 1] : 0;
        //     for (int i = index; i < ItemCount; i++)
        //     {
        //         AnchorCache[index] = anchor;
        //         anchor += SizeCache[i];
        //     }
        // }

        public override void UpdateVisibleItemCount()
        {
            VisibleItemCount = 0;
            if (SizeCache == null || SizeCache.Count == 0) return;
            int index = GetStartIndex();
            float height = -SizeCache[index];
            while (index < ItemCount && height < Height)
            {
                height += SizeCache[index];
                index++;
                VisibleItemCount++;
            }
        }

        public override Vector2 GetItemPosition(int index)
        {
            return new Vector2(0, -AnchorCache[index]) - new Vector2(0, HeaderViewSize);
        }

        public override int GetItemIndex(Vector2 vector2)
        {
            float pos = Orientation == Orientation.Horizontal
                ? 0
                : vector2.y + ContentTransform.anchoredPosition.y - HeaderViewSize;
            int index = Algorithm.BinarySearchFloat(AnchorCache, pos);
            // Debug.Log(UIConstant.Normalize(pos));
            // Debug.Log($"onItemSelectedListener index:{index}");
            if (index >= ItemCount)
            {
                if (pos > AnchorFooter + FooterViewSize)
                    index = -4;
                else
                    index = -3;
            }

            return index;
        }

        protected override int GetStartIndex()
        {
            return GetStartIndex(ContentTransform.anchoredPosition.y - HeaderViewSize);
        }

        protected int GetStartIndex(float position)
        {
            StartIndex = Algorithm.BinarySearchFloat(AnchorCache, 0, ItemCount, position);
            if (StartIndex < 0) StartIndex = 0;
            return StartIndex;
        }

        public override void Internal_Refresh()
        {
            // 停止滚动
            ScrollRect.StopMovement();
            if (Adapter == null) return;

            if (Adapter.GetCount() == ItemCount) return;

            UpdateSizeCache();
            UpdateContentSize();
            StartIndex = GetStartIndex();
            UpdateVisibleItemCount();
            
            // List<AdapterCellHolder> cells = new List<AdapterCellHolder>();
            // for (int i = 0; i < VisibleItemCount; i++)
            // {
            //     LinkedListNode<AdapterCellHolder> node = Items.First;
            //     cells.Add(node == null ? new AdapterCellHolder() : node.Value);
            //     if (Items.Count > 0) Items.RemoveFirst();
            // }
            //
            // foreach (var item in Items)
            // {
            //     Cache.Enqueue(item);
            // }
            //
            // Items.Clear();
            //
            // for (int i = 0; i < VisibleItemCount; i++)
            // {
            //     var cell = cells[i];
            //     int index = StartIndex + i;
            //     IViewLayout convertView = Adapter.GetConvertView(index, cell.View);
            //     convertView.ParentView = ContentView;
            //     var size = Orientation == Orientation.Horizontal
            //         ? new Vector2(SizeCache[index], Height)
            //         : new Vector2(Width, SizeCache[index]);
            //     cell.Update(convertView, index, GetItemPosition(index), size);
            //     Items.AddLast(cell);
            // }
        }

        public override void Reload()
        {
            // 停止滚动
            ScrollRect.StopMovement();
            if (Adapter == null) return;

            // Reload方法会重新建立缓存
            ReloadSizeCache();
            UpdateContentSize();
            StartIndex = GetStartIndex();
            UpdateVisibleItemCount();

            List<AdapterCellHolder> cells = new List<AdapterCellHolder>();
            for (int i = 0; i < VisibleItemCount; i++)
            {
                LinkedListNode<AdapterCellHolder> node = Items.First;
                cells.Add(node == null ? new AdapterCellHolder() : node.Value);
                if (Items.Count > 0) Items.RemoveFirst();
            }

            foreach (var item in Items)
            {
                Cache.Enqueue(item);
            }

            Items.Clear();

            for (int i = 0; i < VisibleItemCount; i++)
            {
                var cell = cells[i];
                int index = StartIndex + i;
                IViewLayout convertView = Adapter.GetConvertView(index, cell.View);
                convertView.ParentView = ContentView;
                var size = Orientation == Orientation.Horizontal
                    ? new Vector2(SizeCache[index], Height)
                    : new Vector2(Width, SizeCache[index]);
                cell.Update(convertView, index, GetItemPosition(index), size);
                Items.AddLast(cell);
            }
        }

        // 记录上次更新的位置
        protected Vector2 LastRepositionPosition = Vector2.zero;

        /// <summary>
        /// 视图在滚动时的回调方法
        /// </summary>
        public override void LayoutSubviews()
        {
            UpdateVisibleItemCount();
            float delta = Orientation == Orientation.Horizontal
                ? LastRepositionPosition.x - ContentTransform.anchoredPosition.x
                : ContentTransform.anchoredPosition.y - LastRepositionPosition.y;
            // 通过偏移位置的正负确定视图的行进方向，这决定了双向链表的遍历顺序
            if (delta > 0)
            {
                // 此时视图向上运动，StartIndex 增大 
                LinkedListNode<AdapterCellHolder> node = Items.First;
                int count = 0;
                while (node != null)
                {
                    if (node.Value.Index >= StartIndex) break;
                    count++;
                    node = node.Next;
                }

                for (int i = 0; i < count; i++)
                {
                    Cache.Enqueue(Items.First.Value);
                    Items.RemoveFirst();
                }

                count = Items.Count;
                int missing = VisibleItemCount - count;
                for (int i = 0; i < missing; i++)
                {
                    int index = Items.Count == 0 ? 0 : Items.Last.Value.Index + 1;

                    AdapterCellHolder cellHolder = Cache.Dequeue();
                    IViewLayout viewLayout = Adapter.GetConvertView(index, cellHolder.View);
                    viewLayout.ParentView = ContentView;
                    var size = Orientation == Orientation.Horizontal
                        ? new Vector2(SizeCache[index], Height)
                        : new Vector2(Width, SizeCache[index]);
                    cellHolder.Update(viewLayout, index, GetItemPosition(index), size);
                    Items.AddLast(cellHolder);
                }
            }
            else
            {
                // 此时视图向下运动
                LinkedListNode<AdapterCellHolder> node = Items.Last;
                int count = 0;
                while (node != null)
                {
                    if (node.Value.Index < StartIndex + VisibleItemCount) break;
                    count++;
                    node = node.Previous;
                }

                for (int i = 0; i < count; i++)
                {
                    Cache.Enqueue(Items.Last.Value);
                    Items.RemoveLast();
                }

                count = Items.Count;
                int missing = VisibleItemCount - count;
                for (int i = 0; i < missing; i++)
                {
                    int index = Items.Count == 0 ? 0 : Items.First.Value.Index - 1;
                    if (index < 0) index = 0;

                    AdapterCellHolder cellHolder = Cache.Dequeue();
                    IViewLayout viewLayout = Adapter.GetConvertView(index, cellHolder.View);
                    viewLayout.ParentView = ContentView;
                    var size = Orientation == Orientation.Horizontal
                        ? new Vector2(SizeCache[index], Height)
                        : new Vector2(Width, SizeCache[index]);
                    cellHolder.Update(viewLayout, index, GetItemPosition(index), size);
                    Items.AddFirst(cellHolder);
                }
            }

            LastRepositionPosition = ContentTransform.anchoredPosition;
        }

        public void RepositionFooter()
        {
            Footer.RectTransform.anchoredPosition = Orientation == Orientation.Horizontal
                ? new Vector2(ContentTransform.sizeDelta.x, 0)
                : new Vector2(0, -ContentTransform.sizeDelta.y + FooterViewSize);
        }

        protected override Vector2 UpdateContentSize()
        {
            if (ItemCount == 0) return Vector2.zero;
            ContentTransform.sizeDelta = Orientation == Orientation.Horizontal
                ? new Vector2(HeaderViewSize + FooterViewSize + AnchorCache[ItemCount - 1] + SizeCache[ItemCount - 1],
                    Height)
                : new Vector2(Width,
                    HeaderViewSize + FooterViewSize + AnchorCache[ItemCount - 1] + SizeCache[ItemCount - 1]);
            return ContentTransform.sizeDelta;
        }
    }
}